#include "CalculateSunAngle.h"

// 计算太阳角度
struct SunAngleStruct CalculateSunAngle::caculate(double year, double month, double day, double hour, double minute, double second, double longitude, double latitude){
  long a = (long)(365.25 * (year - 0x1)) + (long)(30.6001 * (0x1 + 0xd)) + 0x1 + hour / 0x18 + 1720981.5;
  long b;
  if (month <= 0x2) {
      b = (long)(365.25 * (year - 0x1)) + (long)(30.6001 * (month + 0xd)) + day + hour / 0x18 + 1720981.5;
  } else {
      b = (long)(365.25 * year) + (long)(30.6001 * (month + 0x1)) + day + hour / 0x18 + 1720981.5;
  }
  long dayOfYear = b - a + 0x1;
  double c = 79.6764 + 0.2422 * (year - 0x7c1) - (long)((year - 0x7c1) / 0x4);
  double d = 0x2 * PI * (dayOfYear - c) / 365.2422;
  double e = 0.3723 + 23.2567 * sin(d) + 0.1149 * sin(0x2 * d) - 0.1712 * sin(0x3 * d) - 0.758 * cos(d) + 0.3656 * cos(0x2 * d) + 0.0201 * cos(0x3 * d);
  double f = e * PI / 0xb4;
  int timeZone = caculateTimeZone(longitude);
  double dLon;
  if (longitude >= 0x0) {
      if (timeZone == -0xd) {
          dLon = longitude - (floor((longitude * 0xa - 0x4b) / 0x96) + 0x1) * 0xf;
      } else {
          dLon = longitude - timeZone * 0xf;
      }
  } else {
      if (timeZone == -0xd) {
          dLon = (floor((longitude * 0xa - 0x4b) / 0x96) + 0x1) * 0xf - longitude;
      } else {
          dLon = timeZone * 0xf - longitude;
      }
  }
  double equationOfTime = 0.0028 - 1.9857 * sin(d) + 9.9059 * sin(0x2 * d) - 7.0924 * cos(d) - 0.6882 * cos(0x2 * d);
  double hourD = hour + minute / 0x3c + second / 0xe10 + dLon / 0xf;
  double g = hourD + equationOfTime / 0x3c;
  double timeAngle = 0xf * (g - 0xc);
  double h = timeAngle * PI / 0xb4;
  double i = latitude * PI / 0xb4;
  double j = asin(sin(i) * sin(f) + cos(i) * cos(f) * cos(h));
  double k = (sin(j) * sin(i) - sin(f)) / cos(j) / cos(i);
  double l = acos(k);
  struct SunAngleStruct sunAngle;

  sunAngle.alt = j * 0xb4 / PI;
  double m = l * 0xb4 / PI;
  
  if (h < 0x0) {
      sunAngle.azi = 0xb4 - m;
  } else {
      sunAngle.azi = 0xb4 + m;
  }
  return sunAngle;
}

// 计算时区
int CalculateSunAngle::caculateTimeZone(double longitude){
  if (fabs((int)longitude % 0xf) <= 7.5) {
      return (int)(longitude / 0xf);
  } else {
      return (int)(longitude / 0xf) + (longitude > 0x0 ? 0x1 : -0x1);
  }
}